1

如何给spring容器注入bean

通过前几篇笔记,总结出有如下的已知方式:

  • 包扫描(@ComponentScan)+ 组件使用注解类(@Controller@Service@Repository@Component);
  • 使用@Bean注解;

这篇笔记将记录给容器注入bean的新方式

@Import注解,快速给容器注入Bean

  • 导入单个

配置我们的配置类,假如现在我们要注入一个Color对象,如何使用@Import注解呢?如下代码所示:

@Configuration
@Import(Color.class)
public class AppConfig3 {

    /*给容器中注册一个bean,类型是方法返回值,id就是方法名称*/
    @Bean
    public Person person() {
        return new Person("Kate", 12);
    }

}

单元测试类:

    public void testImport() {
        AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(AppConfig3.class);
        String[] names = ctx.getBeanDefinitionNames();

        for (String name : names) {
            System.out.println(name);
        }
    }

运行结果:注入了Color对象

org.springframework.context.annotation.internalConfigurationAnnotationProcessor
org.springframework.context.annotation.internalAutowiredAnnotationProcessor
org.springframework.context.annotation.internalRequiredAnnotationProcessor
org.springframework.context.annotation.internalCommonAnnotationProcessor
org.springframework.context.event.internalEventListenerProcessor
org.springframework.context.event.internalEventListenerFactory
appConfig3
com.sff.app.bean.Color
person
  • 导入多个的方式

@Import({Color.class,Person.class})
使用@Import注解时,容器就会自动注册这个类,bean的id默认是全类名;

使用ImportSelector接口

ImprotSelector接口定义如下

package org.springframework.context.annotation;
import org.springframework.core.type.AnnotationMetadata;

public interface ImportSelector {  
    String[] selectImports(AnnotationMetadata importingClassMetadata);
}

那么如何使用该接口来给容器注册bean呢?当然是要实现该接口了。假如现在要给容器注册Red对象,则进行如下操作:

public class HelloImportSelector implements ImportSelector {
    /**
     * @param importingClassMetadata 标注@Import注解的类的所有注解信息
     * @return 注册到容器的类的全类名
     */
    @Override
    public String[] selectImports(AnnotationMetadata importingClassMetadata) {
        return new String[]{"com.sff.app.bean.Red"};
    }
}

修改配置类即可:

@Configuration
@Import({Color.class,Person.class, HelloImportSelector.class})
public class AppConfig3 {
    /*给容器中注册一个bean,类型是方法返回值,id就是方法名称*/
    @Bean
    public Person person() {
        return new Person("Kate", 12);
    }
}

使用ImportBeanDefinitionRegistrar接口

该接口的内容如下

package org.springframework.context.annotation;

import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor;
import org.springframework.core.type.AnnotationMetadata;

public interface ImportBeanDefinitionRegistrar {
    public void registerBeanDefinitions(
            AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry);
}

那么现在想给容器注入一个Yellow类对象,操作过程如下
实现ImportBeanDefinitionRegistrar 接口

public class HelloBeanRegistrar implements ImportBeanDefinitionRegistrar{

    @Override
    public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata,
                                        BeanDefinitionRegistry registry) {
        /*判断容器中是否存在 Red 对象*/
        boolean red = registry.containsBeanDefinition("com.sff.app.bean.Red");

        if(red){
            /*定义一个注册对象 Yellow,这里可以知道Yellow的相关信息*/
            RootBeanDefinition beanDefinition = new RootBeanDefinition(Yellow.class);
            /*注册一个bean*/
            registry.registerBeanDefinition("yellow",beanDefinition);
        }
    }

修改配置类

@Configuration
@Import({Color.class,Person.class, HelloImportSelector.class, HelloBeanRegistrar.class})
public class AppConfig3 {

    /*给容器中注册一个bean,类型是方法返回值,id就是方法名称*/
    @Bean
    public Person person() {
        return new Person("Kate", 12);
    }
}

使用FactoryBean

还是以给容器注入Color对象进行说明,实现FactoryBean接口

public class ColorFactoryBean implements FactoryBean<Color> {
    @Nullable
    @Override
    public Color getObject() throws Exception {
        return new Color();
    }

    @Nullable
    @Override
    public Class<?> getObjectType() {
        return Color.class;
    }

    /*指定是否单例*/
    @Override
    public boolean isSingleton() {
        return true;
    }
}

配置类中配置ColorFactoryBean对象

@Configuration
@Import({Person.class, HelloImportSelector.class, HelloBeanRegistrar.class})
public class AppConfig3 {
    @Bean
    public ColorFactoryBean colorFactoryBean() {
        return new ColorFactoryBean();
    }
}

单元测试

public void testImport() {
        AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(AppConfig3.class);
        String[] names = ctx.getBeanDefinitionNames();

        for (String name : names) {
            System.out.println(name);
        }

        Object colorFactoryBean = ctx.getBean("colorFactoryBean");
        System.out.println("获取colorFactoryBean的类型:"+colorFactoryBean.getClass());
    }

运行结果如下:

org.springframework.context.annotation.internalConfigurationAnnotationProcessor
org.springframework.context.annotation.internalAutowiredAnnotationProcessor
org.springframework.context.annotation.internalRequiredAnnotationProcessor
org.springframework.context.annotation.internalCommonAnnotationProcessor
org.springframework.context.event.internalEventListenerProcessor
org.springframework.context.event.internalEventListenerFactory
appConfig3
com.sff.app.bean.Person
com.sff.app.bean.Red
colorFactoryBean
person
yellow
获取colorFactoryBean的类型:class com.sff.app.bean.Color

从运行结果发现,在配置类中配置ColorFactoryBean注入到容器中并不是它本身,而是Color对象,那如果要获取ColorFactoryBean本身,使用

AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(AppConfig3.class);
Object colorFactoryBean = ctx.getBean("&colorFactoryBean");

就可以了。

总结

如何给容器中注册Bean?

  • 包扫描(@ComponentScan)+ 组件使用注解类(@Controller@Service@Repository@Component);
  • 使用@Bean注解;
  • 使用@Import注解注解;

    • @Import快速注册
    • 实现ImportSelector接口
    • 实现ImportBeanDefinitionRegistrar接口
  • 使用FactoryBean接口;

一只小小鸟
144 声望25 粉丝

如何做一个深层次的思考者,从简单开始、从记录开始。